home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / DELPHI32 / GRIDS / MSTRGRID / MSTRLIST.PAS < prev    next >
Pascal/Delphi Source File  |  1996-06-17  |  15KB  |  476 lines

  1. unit mstrlist;
  2.  
  3. (* Version 1.0,  10.6.1996,  Freeware, Albrecht Mengel, mengel@stat-econ.uni-kiel.de
  4.  
  5. This is a sister of TStringList with some new sorting properties:
  6.  
  7. property KeyType:(soString,soStringCaseSensitive,soNumeric)
  8.    This is the kind, how the keys (and cells) are compared.
  9.    If you work with soNumeric, all non numbers get the same value 0.
  10.       As these zero values would flip in random order a (case insensitive) string sort
  11.       is performed after. So, first come the negatives, then the strings, and thereafter
  12.       the positives.
  13. property KeyPos:Integer;
  14. property KeyLen:Integer;
  15.    Here you may define, which substring of the cells is used to comparision.
  16.    (Default is KeyPos=1 & KeyLen=MaxInt)
  17. property ScipFirst:Integer;
  18.    Here you can exclude some first entries from sorting.
  19.    (It is used by mStringGrid for excluding fixed rows/cols)
  20.  
  21. When you set sorting to true then the sorting is done with the new properties.
  22. The default settings result in the same sorting as TStringList does.
  23.  
  24. TmStrList is a copy of TStringList found in \source\vcl\grids.pas with some additional
  25. entries.
  26. I had a problem with compiling TStringList.Changed and TStringList.Changing:
  27. They call the property FUpdateCount which I could not reach:
  28.  
  29. procedure TmStrList.Changed;
  30. begin
  31.   if {!(FUpdateCount = 0) and} Assigned(FOnChange) then FOnChange(Self);
  32. end;
  33.  
  34. procedure TmStrList.Changing;
  35.   ... the same ...
  36.  
  37. Is there anyone to fix that problem???
  38.  
  39. Software development:
  40.  
  41. Programming consumes time, and programmed components save time.
  42. If you like my components feel free to send me some acknowledgment.
  43. I accept post cards of your town, money or cheques (2$ up to 20$).
  44. This is a motivation for me to continue developing for you.
  45.  
  46. If you have some ideas to improve mStrList, mStrGrid or any other component
  47. send me a message.
  48.  
  49. The mStrList is copyright (C) 1996, by Albrecht Mengel. You may give copies to
  50. others by copying the original, unmodified zip file. You may use this component
  51. in your own projects free of charge as long as those projects are public domain,
  52. freeware or shareware project.
  53.  
  54. The author of mStrList (A. Mengel) makes no warranty of any kind,
  55. expressed or implied, including without limitation any warranties of merchantability
  56. and/or fitness for a particular purpose. In no event will the author be liable to you
  57. for any additional damages, including any lost profits, lost savings, or other
  58. incidental or consequential damages arising from the use of, or inability to use,
  59. this software and its accompanying documentation, even if the author has been advised
  60. of the possibility of such damages.
  61.  
  62. Albrecht Mengel, University of Kiel, Germany
  63. Institute for Statistics & Economics
  64. Olshausenstrasse 40-60,
  65. D-24098 Kiel
  66. Tel. +49-431-880-2424
  67. Fax. +49-431-880-2673
  68. Email: mengel@stat-econ.uni-kiel.de
  69. http://www.stat-econ.uni-kiel.de/pers/mengel.htm
  70. *)
  71.  
  72. {$R-}
  73.  
  74. interface
  75.  
  76. uses classes;
  77.  
  78. type
  79.  
  80.   TMSortType = (soString,soStringCaseSensitive,soNumeric);
  81.   TmStrList = class(TStrings)
  82.   private
  83.     fKeyType:TMSortType;
  84.     fKeyLen:Integer;
  85.     fKeyPos:Integer;
  86.     fScipFirst:Integer;
  87.     FList: PStringItemList;
  88.     FCount: Integer;
  89.     FCapacity: Integer;
  90.     FSorted: Boolean;
  91.     FDuplicates: TDuplicates;
  92.     FOnChange: TNotifyEvent;
  93.     FOnChanging: TNotifyEvent;
  94.     procedure SetKeyType(value:TMSortType);
  95.     procedure SetKeyLen(value:Integer);
  96.     procedure SetKeyPos(value:Integer);
  97.     procedure ExchangeItems(Index1, Index2: Integer);
  98.     procedure Grow;
  99.     procedure QuickSort(L, R: Integer);
  100.     procedure InsertItem(Index: Integer; const S: string);
  101.     procedure SetCapacity(NewCapacity: Integer);
  102.     procedure SetSorted(Value: Boolean);
  103.     procedure Sort_Alpha;
  104.   protected
  105.     procedure Changed; virtual;
  106.     procedure Changing; virtual;
  107.     function Get(Index: Integer): string; override;
  108.     function GetCount: Integer; override;
  109.     function GetObject(Index: Integer): TObject; override;
  110.     procedure Put(Index: Integer; const S: string); override;
  111.     procedure PutObject(Index: Integer; AObject: TObject); override;
  112.     procedure SetUpdateState(Updating: Boolean); override;
  113.   public
  114.     constructor create;
  115.     destructor Destroy; override;
  116.     function Add(const S: string): Integer; override;
  117.     procedure Clear; override;
  118.     procedure Delete(Index: Integer); override;
  119.     procedure Exchange(Index1, Index2: Integer); override;
  120.     function Find(const S: string; var Index: Integer): Boolean; virtual;
  121.     function IndexOf(const S: string): Integer; override;
  122.     procedure Insert(Index: Integer; const S: string); override;
  123.     procedure Sort; virtual;
  124.     property Duplicates: TDuplicates read FDuplicates write FDuplicates;
  125.     property Sorted: Boolean read FSorted write SetSorted;
  126.     property OnChange: TNotifyEvent read FOnChange write FOnChange;
  127.     property OnChanging: TNotifyEvent read FOnChanging write FOnChanging;
  128.     property KeyType:TMSortType read fKeyType write SetKeyType;
  129.     property KeyLen:Integer read fKeyLen write SetKeyLen;
  130.     property KeyPos:Integer read fKeyPos write SetKeyPos;
  131.     property ScipFirst:Integer read fScipFirst write fScipFirst;
  132.   published
  133.   end;
  134.  
  135. implementation
  136.  
  137. uses SysUtils, Consts;
  138.  
  139. FUNCTION rVAL(CONST von:String):Real;
  140.   {Reads a real value out of the string without an error message.
  141.    Returns 0 if no numeric value}
  142.   VAR bis,err:Integer; nach:Real;
  143.   BEGIN VAL(von,nach,bis);
  144.       IF bis>0 THEN VAL(copy(von,1,bis-1),nach,err);
  145.       rVAL:=nach
  146.   END;{rVAL}
  147.  
  148. constructor TmStrList.create;
  149. begin fKeyPos:=1;
  150.       fKeyLen:=MaxInt;
  151. end;
  152.  
  153. procedure TmStrList.SetKeyType(value:TMSortType);
  154. begin if value<>fKeyType then
  155.       begin fKeyType:=value;
  156.             if FSorted and (fCount>1)  then
  157.              begin Changing;
  158.                    QuickSort(fScipFirst,fCount-1);
  159.                    if fKeyType=soNumeric then Sort_Alpha;
  160.                    Changed;
  161. end   end    end;
  162.  
  163. procedure TmStrList.SetKeyLen(value:Integer);
  164. begin if value<>fKeyLen then
  165.       begin if value<1 then value:=1;
  166.             {showmessage('Keylen: '+inttostr(fKeylen)+' -> '+inttostr(value));}
  167.             fKeyLen:=value;
  168.             if FSorted and (fCount>1)  then
  169.              begin Changing;
  170.                    QuickSort(fScipFirst,fCount-1);
  171.                    if fKeyType=soNumeric then Sort_Alpha;
  172.                    Changed;
  173. end   end    end;
  174.  
  175. procedure TmStrList.SetKeyPos(value:Integer);
  176. begin if value<>fKeyPos then
  177.       begin if value<1 then value:=1;
  178.             {showmessage('KeyPos: '+inttostr(fKeypos)+' -> '+inttostr(value));}
  179.             fKeyPos:=value;
  180.             if FSorted and (fCount>1) then
  181.              begin Changing;
  182.                    QuickSort(fScipFirst,fCount-1);
  183.                    if fKeyType=soNumeric then Sort_Alpha;
  184.                    Changed;
  185. end   end    end;
  186.  
  187. procedure TmStrList.QuickSort(L, R: Integer);
  188. var
  189.   I, J: Integer;
  190.   P: string; Pr:Real;
  191. begin
  192.   case fKeyType of
  193.    soString:  repeat I := L; J := R;
  194.                      P := copy(FList^[(L + R) shr 1].FString,fKeyPos,fKeyLen);
  195.                      repeat while AnsiCompareText(copy(FList^[I].FString,fKeyPos,fKeyLen),P)<0 do Inc(I);
  196.                             while AnsiCompareText(copy(FList^[J].FString,fKeyPos,fKeyLen),P)>0 do Dec(J);
  197.                             if I <= J then begin
  198.                                ExchangeItems(I, J);
  199.                                Inc(I);      Dec(J);
  200.                             end;
  201.                      until I > J;
  202.                      if L < J then QuickSort(L, J);
  203.                      L := I;
  204.               until I >= R;
  205.    soStringCaseSensitive:
  206.               repeat I := L; J := R;
  207.                      P := copy(FList^[(L + R) shr 1].FString,fKeyPos,fKeyLen);
  208.                      repeat while copy(FList^[I].FString,fKeyPos,fKeyLen)<P do Inc(I);
  209.                             while copy(FList^[J].FString,fKeyPos,fKeyLen)>P do Dec(J);
  210.                             if I <= J then begin
  211.                                ExchangeItems(I, J);
  212.                                Inc(I);      Dec(J);
  213.                             end;
  214.                      until I > J;
  215.                      if L < J then QuickSort(L, J);
  216.                      L := I;
  217.               until I >= R;
  218.    soNumeric: repeat I := L; J := R;
  219.                      Pr:= Rval(copy(FList^[(L + R) shr 1].FString,fKeyPos,fKeyLen));
  220.                      repeat while Rval(copy(FList^[I].FString,fKeyPos,fKeyLen))<Pr do Inc(I);
  221.                             while Rval(copy(FList^[J].FString,fKeyPos,fKeyLen))>Pr do Dec(J);
  222.                             if I <= J then begin
  223.                                ExchangeItems(I, J);
  224.                                Inc(I);      Dec(J);
  225.                             end;
  226.                      until I > J;
  227.                      if L < J then QuickSort(L, J);
  228.                      L := I;
  229.               until I >= R;
  230.   end
  231. end;
  232.  
  233. procedure ListError(Ident: Integer);
  234. begin
  235.   raise EListError.CreateRes(Ident);
  236. end;
  237.  
  238. procedure ListIndexError;
  239. begin
  240.   ListError(SListIndexError);
  241. end;
  242.  
  243. destructor TmStrList.Destroy;
  244. begin
  245.   FOnChange := nil;
  246.   FOnChanging := nil;
  247.   if FCount <> 0 then Finalize(FList^[0], FCount);
  248.   FCount := 0;
  249.   SetCapacity(0);
  250. end;
  251.  
  252. function TmStrList.Add(const S: string): Integer;
  253. begin
  254.   if not Sorted then
  255.     Result := FCount
  256.   else
  257.     if Find(S, Result) then
  258.       case Duplicates of
  259.         dupIgnore: Exit;
  260.         dupError: ListError(SDuplicateString);
  261.       end;
  262.   InsertItem(Result, S);
  263. end;
  264.  
  265. procedure TmStrList.Changed;
  266. begin
  267.   if {!(FUpdateCount = 0) and} Assigned(FOnChange) then FOnChange(Self);
  268. end;
  269.  
  270. procedure TmStrList.Changing;
  271. begin
  272.   if {!(FUpdateCount = 0) and} Assigned(FOnChanging) then FOnChanging(Self);
  273. end;
  274.  
  275. procedure TmStrList.Clear;
  276. begin
  277.   if FCount <> 0 then
  278.   begin
  279.     Changing;
  280.     Finalize(FList^[0], FCount);
  281.     FCount := 0;
  282.     SetCapacity(0);
  283.     Changed;
  284.   end;
  285. end;
  286.  
  287. procedure TmStrList.Delete(Index: Integer);
  288. begin
  289.   if (Index < 0) or (Index >= FCount) then ListIndexError;
  290.   Changing;
  291.   Finalize(FList^[Index]);
  292.   Dec(FCount);
  293.   if Index < FCount then
  294.     System.Move(FList^[Index + 1], FList^[Index],
  295.       (FCount - Index) * SizeOf(TStringItem));
  296.   Changed;
  297. end;
  298.  
  299. procedure TmStrList.Exchange(Index1, Index2: Integer);
  300. begin
  301.   if (Index1 < 0) or (Index1 >= FCount) or
  302.     (Index2 < 0) or (Index2 >= FCount) then ListIndexError;
  303.   Changing;
  304.   ExchangeItems(Index1, Index2);
  305.   Changed;
  306. end;
  307.  
  308. procedure TmStrList.ExchangeItems(Index1, Index2: Integer);
  309. var
  310.   Temp: Integer;
  311.   Item1, Item2: PStringItem;
  312. begin
  313.   Item1 := @FList^[Index1];
  314.   Item2 := @FList^[Index2];
  315.   Temp := Integer(Item1^.FString);
  316.   Integer(Item1^.FString) := Integer(Item2^.FString);
  317.   Integer(Item2^.FString) := Temp;
  318.   Temp := Integer(Item1^.FObject);
  319.   Integer(Item1^.FObject) := Integer(Item2^.FObject);
  320.   Integer(Item2^.FObject) := Temp;
  321. end;
  322.  
  323. function TmStrList.Find(const S: string; var Index: Integer): Boolean;
  324. var
  325.   L, H, I, C: Integer;
  326. begin
  327.   Result := False;
  328.   L := 0;
  329.   H := FCount - 1;
  330.   while L <= H do
  331.   begin
  332.     I := (L + H) shr 1;
  333.     C := AnsiCompareText(FList^[I].FString, S);
  334.     if C < 0 then L := I + 1 else
  335.     begin
  336.       H := I - 1;
  337.       if C = 0 then
  338.       begin
  339.         Result := True;
  340.         if Duplicates <> dupAccept then L := I;
  341.       end;
  342.     end;
  343.   end;
  344.   Index := L;
  345. end;
  346.  
  347. function TmStrList.Get(Index: Integer): string;
  348. begin
  349.   if (Index < 0) or (Index >= FCount) then ListIndexError;
  350.   Result := FList^[Index].FString;
  351. end;
  352.  
  353. function TmStrList.GetCount: Integer;
  354. begin
  355.   Result := FCount;
  356. end;
  357.  
  358. function TmStrList.GetObject(Index: Integer): TObject;
  359. begin
  360.   if (Index < 0) or (Index >= FCount) then ListIndexError;
  361.   Result := FList^[Index].FObject;
  362. end;
  363.  
  364. procedure TmStrList.Grow;
  365. var
  366.   Delta: Integer;
  367. begin
  368.   if FCapacity > 8 then Delta := 16 else
  369.     if FCapacity > 4 then Delta := 8 else
  370.       Delta := 4;
  371.   SetCapacity(FCapacity + Delta);
  372. end;
  373.  
  374. function TmStrList.IndexOf(const S: string): Integer;
  375. begin
  376.   if not Sorted then Result := inherited IndexOf(S) else
  377.     if not Find(S, Result) then Result := -1;
  378. end;
  379.  
  380. procedure TmStrList.Insert(Index: Integer; const S: string);
  381. begin
  382.   if Sorted then ListError(SSortedListError);
  383.   if (Index < 0) or (Index > FCount) then ListIndexError;
  384.   InsertItem(Index, S);
  385. end;
  386.  
  387. procedure TmStrList.InsertItem(Index: Integer; const S: string);
  388. begin
  389.   Changing;
  390.   if FCount = FCapacity then Grow;
  391.   if Index < FCount then
  392.     System.Move(FList^[Index], FList^[Index + 1],
  393.       (FCount - Index) * SizeOf(TStringItem));
  394.   with FList^[Index] do
  395.   begin
  396.     Pointer(FString) := nil;
  397.     FObject := nil;
  398.     FString := S;
  399.   end;
  400.   Inc(FCount);
  401.   Changed;
  402. end;
  403.  
  404. procedure TmStrList.Put(Index: Integer; const S: string);
  405. begin
  406.   if Sorted then ListError(SSortedListError);
  407.   if (Index < 0) or (Index >= FCount) then ListIndexError;
  408.   Changing;
  409.   FList^[Index].FString := S;
  410.   Changed;
  411. end;
  412.  
  413. procedure TmStrList.PutObject(Index: Integer; AObject: TObject);
  414. begin
  415.   if (Index < 0) or (Index >= FCount) then ListIndexError;
  416.   Changing;
  417.   FList^[Index].FObject := AObject;
  418.   Changed;
  419. end;
  420.  
  421. procedure TmStrList.SetCapacity(NewCapacity: Integer);
  422. begin
  423.   ReallocMem(FList, NewCapacity * SizeOf(TStringItem));
  424.   FCapacity := NewCapacity;
  425. end;
  426.  
  427. procedure TmStrList.SetSorted(Value: Boolean);
  428. begin
  429.   if FSorted <> Value then
  430.   begin
  431.     if Value then Sort;
  432.     FSorted := Value;
  433.   end;
  434. end;
  435.  
  436. procedure TmStrList.SetUpdateState(Updating: Boolean);
  437. begin
  438.   if Updating then Changing else Changed;
  439. end;
  440.  
  441. procedure TmStrList.Sort;
  442. begin
  443.   if not Sorted and (FCount > 1) then
  444.   begin
  445.     Changing;
  446.     QuickSort(fScipFirst, FCount - 1);
  447.     if fKeyType=soNumeric then Sort_Alpha;
  448.     Changed;
  449.   end;
  450. end;
  451.  
  452. procedure TmStrList.Sort_Alpha;
  453. var anfang,ende:integer; found:boolean;
  454. begin {soNumeric : die Alpha-EintrΣge nachsortieren}
  455.       anfang:=fScipFirst;
  456.       found:=false;
  457.       while anfang<fCount do
  458.        if rval(copy(FList^[anfang].FString,fKeyPos,fKeyLen))<>0
  459.         then inc(anfang)
  460.         else begin found:=true;
  461.                    break
  462.              end;
  463.       if not found then exit;
  464.       ende:=anfang+1;
  465.       while ende<fCount do
  466.        if rval(copy(FList^[ende].FString,fKeyPos,fKeyLen))=0
  467.         then inc(ende)
  468.         else break;
  469.       if anfang<ende-1 then
  470.       begin fKeyType:=soString;
  471.             QuickSort(anfang,ende-1);
  472.             fKeyType:=soNumeric
  473. end   end;
  474.  
  475. end.
  476.